﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace LightParallelLibrary
{
    /// <summary>
    /// Thread Safe TPQueue
    /// </summary>
    /// <typeparam name="T">The TPQueue Element type</typeparam>
    internal class TPQueue
    {
        sealed class TPQueueElement
        {
            public bool Removed;
            public QueueTask Value;
            public TPQueueElement Prev, Next;

            public TPQueueElement(QueueTask value)
            {
                Removed = false;
                Value = value; Prev = null; Next = null;
            }
        }

        /*/////////////////////////////////////////////////////////////////////////////*/

        int count;
        TPQueueElement First, Last;
        object SycObject = new object();

        /*/////////////////////////////////////////////////////////////////////////////*/

        #region Class Constructor

        public TPQueue()
        {
            First = Last = null; count = 0;
        }

        #endregion

        /*/////////////////////////////////////////////////////////////////////////////*/

        #region TPQueue Operations

        /// <summary>
        /// Add item to the TPQueue
        /// </summary>
        /// <param name="Value"></param>
        public void EnQueue(QueueTask Value)
        {
            TPQueueElement tmp = new TPQueue.TPQueueElement(Value);

            Monitor.Enter(SycObject);

            if (count == 0)
            {
                First = Last = tmp; ++count;
            }
            else
            {
                tmp.Prev = Last;
                Last.Next = tmp;
                Last = tmp;
                ++count;
            }

            Monitor.Exit(SycObject);
        }

        /// <summary>
        /// Get Item from the TPQueue
        /// </summary>
        /// <returns></returns>
        public QueueTask DeQueue()
        {
            Monitor.Enter(SycObject);

            if (count == 0) 
            {
                Monitor.Exit(SycObject);
                return null;
            } 

            QueueTask tmp = First.Value;

            if (count == 1)
                First = Last = null;
            else
            {
                First = First.Next;
                First.Prev = null;
            }

            --count;

            Monitor.Exit(SycObject);

            return tmp;
        }

        /// <summary>
        /// Remove every element that Identity equal the Identity parameter. Just mark it.
        /// </summary>
        /// <param name="Identity"></param>
        public void Remove(string Identity)
        {
            Monitor.Enter(SycObject);

            TPQueueElement tmp = First;

            while (tmp != null)
            {
                if (tmp.Value.identity == Identity)
                {
                    --count;
                    if (tmp == Last) Last = tmp.Prev;
                    if (tmp == First) First = tmp.Next;

                    if (tmp.Prev != null) tmp.Prev.Next = tmp.Next;
                    if (tmp.Next != null) tmp.Next.Prev = tmp.Prev;
                }
                tmp = tmp.Next;
            }

            Monitor.Exit(SycObject);
        }

        /// <summary>
        /// The Count of queue elements
        /// </summary>
        public int Count
        {
            get 
            {
                Monitor.Enter(SycObject);
                int r = count;
                Monitor.Exit(SycObject);
                return r;
            }
        }

        #endregion

    }
}
